package com.zzyl.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.CacheConstants;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.LoginDto;
import com.zzyl.dto.UserDto;
import com.zzyl.entity.User;
import com.zzyl.entity.UserRole;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.UserMapper;
import com.zzyl.mapper.UserRoleMapper;
import com.zzyl.properties.JwtTokenManagerProperties;
import com.zzyl.properties.SecurityConfigProperties;
import com.zzyl.service.UserService;
import com.zzyl.utils.JwtUtil;
import com.zzyl.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private JwtTokenManagerProperties jwtTokenManagerProperties;

    @Autowired
    private SecurityConfigProperties securityConfigProperties;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public PageResponse<UserVo> findByPage(UserDto userDto, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        Page<UserVo> page = (Page<UserVo>)userMapper.findList(userDto);
        return PageResponse.of(page,UserVo.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addUser(UserDto userDto) {
        // 一 保存用户表
        User user = BeanUtil.toBean(userDto, User.class);

        String password =BCrypt.hashpw("888itcast.CN764%..."); //这里的密码从登录页面的密码框中获取
        user.setPassword(password);
        user.setUsername(user.getEmail()); //把邮箱赋值到用户名中
        userMapper.insert(user);

        // 二 保存用户角色中间表
        Set<String> roleVoIds = userDto.getRoleVoIds();
        List<UserRole> list = new ArrayList<>();
        for (String roleVoId : roleVoIds) {
            UserRole userRole = new UserRole(user.getId(), Long.parseLong(roleVoId), "0");
            list.add(userRole);
        }


        // 批量保存
        userRoleMapper.batchInsert(list);
        return true;
    }

    @Override
    public UserVo login(LoginDto loginDto) {

        // select * from sys_user where username=#{username} and password=md5(#{password})


        // 1、根据用户名查询用户
        User user = userMapper.findByUsername(loginDto.getUsername());
        if(ObjectUtil.isEmpty(user)){
            throw new BaseException(BasicEnum.LOGIN_FAIL);
        }
        // 2、判断是否被禁用
        if (user.getDataState().equals(SuperConstant.DATA_STATE_1)) {
            throw new BaseException(BasicEnum.ACCOUNT_LOCK); // 自己新增的一个枚举
        }
        // 3、判断密码是否正确
        if (!BCrypt.checkpw(loginDto.getPassword(), user.getPassword())) {
            throw new BaseException(BasicEnum.USERNAME_OR_PASSWORD_ERROR);  // 自己新增的一个枚举
        }
        // 4、密码脱敏：不用把密码返回给前端
        user.setPassword("");

        UserVo userVo = BeanUtil.toBean(user, UserVo.class);

        // 5、使用JWT工具生成jwt的字符串
        Map<String, Object> claims = new HashMap<>();
        claims.put("currentUser", JSONUtil.toJsonStr(userVo));

        String token = JwtUtil.createJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey(), jwtTokenManagerProperties.getTtl(), claims);
        userVo.setUserToken(token);

        // 6、获取白名单
        List<String> publicAccessUrls = securityConfigProperties.getPublicAccessUrls();
        // 7、获取当前登录人的按钮资源  涉及SQL语句的查询
        List<String> urls = userMapper.findResurceByUserId(user.getId());

        // 8、合并两个资源
        urls.addAll(publicAccessUrls);
        // 9、放到Redis中  JSON.toStr(urls)

        redisTemplate.boundValueOps(CacheConstants.PUBLIC_ACCESS_URLS+user.getId()).set(JSONUtil.toJsonStr(urls),jwtTokenManagerProperties.getTtl(), TimeUnit.HOURS);//        string



        return userVo;
    }
}
